/*
 * TCSS 422.
 * Project 2.
 */
import java.util.Random;
/**
 * IODevice.java.
 * @author Levon Keichichian.
 * @author Khanh Nguyen
 * @author Thang Tran
 * @author Gian Bata.
 *
 */
public class IODevice implements Runnable
{
	private static final int LOWERBOUND_WAIT = 10000;
	private String my_name;
	private volatile boolean my_status_flag;
	private volatile boolean my_done_flag;
	private int my_id;
	private volatile ProcessControlBlock my_pcb;
	private CPU my_cpu;
	private Random my_random_generator;
	
	public IODevice(final int the_id, final String the_name)
	{
		my_id = the_id;
		my_name = the_name;
		my_random_generator = new Random();
		my_random_generator.setSeed(System.nanoTime());
		my_done_flag = true;
		my_status_flag = false;
	}
	
	public void setCPU(final CPU the_cpu)
	{
		my_cpu = the_cpu;
	}
	
	public CPU getCPU()
	{
		return my_cpu;
	}
	
	public ProcessControlBlock getPCB()
	{
		return my_pcb;
	}
	
	public void setPCB(final ProcessControlBlock the_pcb)
	{
		my_pcb = the_pcb;
	}
	
	public String getName()
	{
		return my_name;
	}
	
	public int getId()
	{
		return my_id;
	}
	
	public int generateRandomNumber()
	{
		return Math.abs(my_random_generator.nextInt());
	}
	
	private void sendInterrupt()
	{
		my_cpu.handleInterrupt(this);
	}
	
	public synchronized void notifyThread()
	{
		my_status_flag = !my_status_flag;
		notifyAll();
	}
	
	public String toString()
	{
		final StringBuffer str = new StringBuffer();
		
		str.append("Device ").append(my_id);
		str.append(" (").append(my_name);
		str.append(") produced an interrupt\n");
		
		return str.toString();
	}
	
	public void stop()
	{
		my_done_flag = false;
	}

	@Override
	public void run() 
	{
		while (my_done_flag)
		{
			synchronized(this)
			{
				while (!my_status_flag)
				{
					try
					{
						wait();
						int random_number = 1000 + Math.abs(my_random_generator.nextInt() 
								%  LOWERBOUND_WAIT);
						Thread.sleep(random_number);
					}
					catch (final InterruptedException the_exception)
					{
						System.out.println(getClass().getName() + " interrupted");
					}
				}
				sendInterrupt();
				my_status_flag = false;
			}
		}
	}
}
